#include <string.h>
#include "door_common.h"
#include "gkt_io_debounce.h"
#include "gkt_door.h"

#if defined(GKT_CONFIG_DOOR_LOCK_ENABLE) && GKT_CONFIG_DOOR_LOCK_ENABLE \
	&& defined(GKT_CONFIG_DOOR_ADMIN_UNLOCK_ENABLE) && GKT_CONFIG_DOOR_ADMIN_UNLOCK_ENABLE

#ifndef GKT_CONFIG_DOOR_ADMIN_UNLOCK_GPIO_PIN
#error "not define GKT_CONFIG_DOOR_ADMIN_UNLOCK_GPIO_PIN"
#endif

#ifndef GKT_CONFIG_DOOR_ADMIN_UNLOCK_DETECT_LEVEL
#error "not define GKT_CONFIG_ADMIN_UNLOCK_DETECT_LEVEL"
#endif

#define DOOR_ADMIN_UNLOCK_DETECT_LEVEL GKT_CONFIG_DOOR_ADMIN_UNLOCK_DETECT_LEVEL
#if (0 == DOOR_ADMIN_UNLOCK_DETECT_LEVEL)
#define DOOR_ADMIN_UNLOCK_GPIO_FLAGS \
	(GKT_GPIO_F_INPUT | GKT_GPIO_F_PULL_UP | GKT_GPIO_F_INT_EDGE_FALL \
		| GKT_GPIO_F_INT_DEBOUNCE | GKT_GPIO_F_INT_MASKED)
#else
#define DOOR_ADMIN_UNLOCK_GPIO_FLAGS	\
	(GKT_GPIO_F_INPUT | GKT_GPIO_F_PULL_DOWN | GKT_GPIO_F_INT_EDGE_RAISE \
		| GKT_GPIO_F_INT_DEBOUNCE | GKT_GPIO_F_INT_MASKED)
#endif

#if defined(GKT_CONFIG_ADMIN_UNLOCK_IO_DEBOUNCE_TIME_MS) \
	&& (GKT_CONFIG_ADMIN_UNLOCK_IO_DEBOUNCE_TIME_MS >= 20)
#define DOOR_ADMIN_UNLOCK_IO_DEBOUNCE_TIME_MS	\
	GKT_CONFIG_ADMIN_UNLOCK_IO_DEBOUNCE_TIME_MS
#else
#define DOOR_ADMIN_UNLOCK_IO_DEBOUNCE_TIME_MS	100
#endif

#define DOOR_ADMIN_UNLOCK_IO_READY	(1U << 0)
#define DOOR_ADMIN_UNLOCK_IO_DEBOUNCE_READY	(1U << 4)
#define DOOR_ADMIN_UNLOCK_IO_DEBOUNCE_BUSY	(1U << 5)
#define DOOR_ADMIN_UNLOCK_IO_DEBOUNCE_COMPLETE	(1U << 6)

typedef struct _door_admin_unlock {
	uint32_t	mask_bits;
	uint32_t	gpio_pin;
	uint32_t	io_debounce_id;
	uint32_t	state;

} door_admin_unlock_s;
static door_admin_unlock_s s_door_admin_unlock;
#if 0
static void door_admin_unlock_detect_notify(uint32_t pin)
{
	int retval;

	gkt_unused(pin);
	if (s_door_admin_unlock.state & DOOR_ADMIN_UNLOCK_IO_READY) 
	{
		gkt_trace("door_admin_unlock_detect_notify: (%u) state(0x%x)\n", s_door_admin_unlock.state);

		if ((s_door_admin_unlock.state & DOOR_ADMIN_UNLOCK_IO_DEBOUNCE_READY)
			&& !(s_door_admin_unlock.state & DOOR_ADMIN_UNLOCK_IO_DEBOUNCE_BUSY)) 
		{
			s_door_admin_unlock.state &= ~(DOOR_ADMIN_UNLOCK_IO_DEBOUNCE_BUSY | DOOR_ADMIN_UNLOCK_IO_DEBOUNCE_COMPLETE);
			retval = gkt_io_debounce_start(s_door_admin_unlock.io_debounce_id, 1, 
							DOOR_ADMIN_UNLOCK_IO_DEBOUNCE_TIME_MS);
			if (GKT_SUCCESS == retval)
				s_door_admin_unlock.state |= DOOR_ADMIN_UNLOCK_IO_DEBOUNCE_BUSY;
		}
	}
}
#endif
static int door_admin_unlock_is_detected(void)
{
	uint32_t level;
	int retval;

	retval = gkt_gpio_get_pin_level(GKT_CONFIG_DOOR_ADMIN_UNLOCK_GPIO_PIN, &level);
	return ((GKT_SUCCESS == retval) && (DOOR_ADMIN_UNLOCK_DETECT_LEVEL == level)) ? 1 : 0;
}
static void door_admin_unlock_debounce_complete(
				int result, int detect_state)
{
	gkt_info("door_admin_unlock_complete: result(%d) state(0x%x)\n", 
		 result, s_door_admin_unlock.state);

	if (s_door_admin_unlock.state & DOOR_ADMIN_UNLOCK_IO_DEBOUNCE_BUSY) {
		s_door_admin_unlock.state &= ~DOOR_ADMIN_UNLOCK_IO_DEBOUNCE_BUSY;

		if (GKT_IO_DEBOUNCE_OK == result) {
			s_door_admin_unlock.state |= DOOR_ADMIN_UNLOCK_IO_DEBOUNCE_COMPLETE;

			//notify app ??
		}
	}
}
int door_admin_unlock_init(void)
{
	gkt_io_debounce_attr_s io_debounce_attr;
	int retval;

	memset(&s_door_admin_unlock, 0, sizeof(s_door_admin_unlock));

	s_door_admin_unlock.gpio_pin = GKT_CONFIG_DOOR_ADMIN_UNLOCK_GPIO_PIN;
	s_door_admin_unlock.io_debounce_id = GKT_IO_DEBOUNCE_ID(door_admin_unlock);

	io_debounce_attr.step_ms = 0;	/* use default settings */
	io_debounce_attr.detect_fn = door_admin_unlock_is_detected;
	io_debounce_attr.complete_fn = door_admin_unlock_debounce_complete;
	retval = gkt_io_debounce_config(s_door_admin_unlock.io_debounce_id, &io_debounce_attr);
	if (GKT_SUCCESS == retval)
		s_door_admin_unlock.state |= DOOR_ADMIN_UNLOCK_IO_DEBOUNCE_READY;
	else
		gkt_error("door_admin_unlock: debounce config failed!\n");

	retval = gkt_gpio_config(GKT_CONFIG_DOOR_ADMIN_UNLOCK_GPIO_PIN,
					DOOR_ADMIN_UNLOCK_GPIO_FLAGS, NULL);
	if (retval != GKT_SUCCESS) {
		gkt_error("door_admin_unlock: <1> config gpio failed %d\n", retval);
		return retval;
	}
	s_door_admin_unlock.state |= DOOR_ADMIN_UNLOCK_IO_READY;

	//gkt_gpio_interrupt_unmask(GKT_CONFIG_DOOR_ADMIN_UNLOCK_GPIO_PIN);

	return GKT_SUCCESS;
}

int gkt_door_admin_unlock_is_detected()
{
	int detected = 0;

	if (s_door_admin_unlock.state & DOOR_ADMIN_UNLOCK_IO_READY) {
		detected = door_admin_unlock_is_detected();	
	}

	return detected;
}

#endif

